package com.justgame.project.service.system.controller;


import com.justgame.project.base.annotation.ProtectAccess;
import com.justgame.project.base.annotation.VerificationCode;
import com.justgame.project.base.utils.EmailUtil;
import com.justgame.project.base.utils.OrderUtil;
import com.justgame.project.cloud.common.constant.Const;
import com.justgame.project.cloud.common.constant.Regex;
import com.justgame.project.cloud.common.constant.Result;
import com.justgame.project.cloud.common.constant.ValidGroup;
import com.justgame.project.cloud.common.enums.TimeEnum;
import com.justgame.project.cloud.common.exception.Exc;
import com.justgame.project.cloud.common.util.*;
import com.justgame.project.service.api.dto.SysUserInfoDTO;
import com.justgame.project.service.system.mapper.SysUserInfoMapper;
import com.justgame.project.service.system.service.SysUserInfoService;
import com.justgame.project.service.system.service.UsualService;
import com.wf.captcha.SpecCaptcha;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;

@Slf4j
@RequestMapping("/sys")
@RestController
@AllArgsConstructor
public class SysController {
    private final RedisUtil redisUtil;
    private final SysUserInfoService sysUserInfoService;
    private final SysUserInfoMapper sysUserInfoMapper;
    private final UsualService usualService;

    private final static String B_VIDEOS_LIST_URL = "http://api.bilibili.com/x/web-interface/search/all/v2";
    /**
     * 账户创建
     *
     * @param sysUserInfoDTO
     * @return
     */
    @PostMapping("/create/account")
    @ProtectAccess(value = 10L, message = "请勿频繁注册账号！")
    public Result<Object> createAccount(@Validated({ValidGroup.Add.class}) @RequestBody SysUserInfoDTO sysUserInfoDTO) {
        if (sysUserInfoService.createAccount(sysUserInfoDTO)) {
            return Result.OK("账户创建成功");
        } else {
            return Result.fail("账户创建失败");
        }
    }

    @PostMapping("/login")
    @VerificationCode
    @ProtectAccess(value = 10L, message = "请勿频繁登录账号！")
    public Result<Object> login(@Validated({ValidGroup.Select.class}) @RequestBody SysUserInfoDTO loginUserModel) {
        return Result.OK(sysUserInfoService.login(loginUserModel));
    }

    /**
     * 重新获取用户信息
     *
     * @return
     */
    @GetMapping("/regain-user-info")
    public Result<Object> regainUserInfo() {
        return Result.OK(sysUserInfoService.regainUserInfo());
    }

    /**
     * 邮箱变更
     *
     * @param dto
     * @return
     */
    @PutMapping("/change-email")
    public Result<Object> changeEmail(@RequestBody SysUserInfoDTO dto) {
        return Result.status(sysUserInfoService.changeEmail(dto));
    }

    @PostMapping("/logout")
    @ProtectAccess(value = 10L, message = "请勿频繁退出登录！")
    public Result<Object> logout() {
        return Result.status(sysUserInfoService.logout());
    }

    @RequestMapping("/commom/403")
    public Result<Object> UnauthorizedUrl() {
        return Result.fail(Const.RES_ERROR_AUTHORIZATION_CHINESE, Const.RES_ERROR_AUTHORIZATION);
    }



    /**
     * 给邮箱发送验证码
     *
     * @param mail
     * @return
     */
    @GetMapping("/email/send-validation")
    public Result<?> email(String mail) {
        /* 检查字段 */
        if (StringUtils.isBlank(mail)) {
            return Result.fail("邮箱地址不能为空！");
        } else if (!Regex.isEmail(mail)) {
            return Result.fail("邮箱格式不正确！");
        }
        boolean emailHasUsed = sysUserInfoMapper.countsOfEmail(mail) > 0;
        if (emailHasUsed) {
            throw new Exc("该邮箱已被使用，无法绑定！");
        }
        /* 判断发送邮件次数 */
        String intStr = redisUtil.get(Const.EMAIL_VALIDATION_COUNT + mail);
        int hasSendCount;
        if (StringUtils.isBlank(intStr)) {
            hasSendCount = 0;
        } else {
            hasSendCount = Integer.parseInt(intStr);
        }
        if (redisUtil.get(Const.EMAIL_VALIDATION_TIMEOUT + mail) != null) {
            return Result.fail("请勿频繁发送邮箱验证码！");
        } else if (hasSendCount == Const.EMAIL_VALIDATION_MAX_COUNT) {
            return Result.fail("您发送验证码次数已达到当日上限，请次日再试！");
        } else {
            hasSendCount += 1;
        }
        /* 生成发送的验证码 */
        String code = OrderUtil.randomNumberStr(6);
        redisUtil.delete(Const.EMAIL_VALIDATION_CODE + mail);
        redisUtil.set(Const.EMAIL_VALIDATION_CODE + mail, code, TimeEnum.MINUTE.getTime(5) / 1000);
        EmailUtil.sendMailCode(mail, code);
        redisUtil.set(Const.EMAIL_VALIDATION_TIMEOUT + mail, System.currentTimeMillis(), TimeEnum.MINUTE.getTime(1) / 1000);
        redisUtil.set(Const.EMAIL_VALIDATION_COUNT + mail, hasSendCount, TimeUtil.getTime2NextDay());
        return Result.OK("发送成功！");
    }



    /**
     * 生成验证码
     *
     * @param response
     */
    @GetMapping("/verification")
    public void buildVerificationCode(HttpServletResponse response) {
        try {
            //AuthCodeUtils.defaultBuild();
            SpecCaptcha specCaptcha = new SpecCaptcha(100, 40, 5);
            String code = specCaptcha.text().toLowerCase();
            StringBuffer sb = Encryption.PasswordMD5(code, Const.DEFAULT_SALT_VERIFICATION);
            String md5VCode = String.valueOf(sb);
            ShiroUtils.setSessionAttribute(Const.KEY_VERIFICATION_CODE_2WEB, md5VCode);
            AppContextUtils.getBean(RedisUtil.class).set(String.valueOf(ShiroUtils.getSession().getId()), md5VCode, TimeEnum.MINUTE.getTime(15) / 1000);
            specCaptcha.out(response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @GetMapping(value = "/queryAllStatusInfo")
    public Result<?> queryAllStatusInfo() {
        List<?> list = redisUtil.getCollection(Const.KEY_REDIS_TOTAL_STATUS);
        return Result.OK(list);
    }

    /**
     * B站获取视频列表接口
     * @return
     */
    @GetMapping("/third-party-api/b")
    public Result<Object> bilibiliVideoList(@RequestParam Map<String, Object> params){
        String url = String.format("%s%s",B_VIDEOS_LIST_URL,HttpUtil.buildUrlParams(params));
        return Result.OK(HttpUtil.get(url));
    }

    /**
     * 查询全部省级区域
     */
    @GetMapping("/area/province")
    public Result<?> queryProvince() {
        return Result.OK(usualService.queryAreas(1));
    }

    /**
     * 通过条件查询省级区域
     */
    @GetMapping("/area/province/{param}")
    public Result<?> queryCityByParentCode(@PathVariable("param") String param) {
        try {
            Integer.parseInt(param);
            return Result.OK(usualService.queryAreaByCode(param));
        } catch (NumberFormatException e) {
            return Result.OK(usualService.queryAreaByName(param, 1));
        }
    }

    /**
     * 查询全部市级区域
     */
    @GetMapping("/area/city")
    public Result<?> queryCity() {
        return Result.OK(usualService.queryAreas(2));
    }

    /**
     * 通过条件查询市级区域
     */
    @GetMapping("/area/city/{param}")
    public Result<?> queryCityBy(@PathVariable("param") String param) {
        try {
            Integer.parseInt(param);
            return Result.OK(usualService.queryAreaByCode(param));
        } catch (NumberFormatException e) {
            return Result.OK(usualService.queryAreaByName(param, 2));
        }
    }

    /**
     * 查询全部市级区域
     */
    @GetMapping("/area/county")
    public Result<?> queryCounty() {
        return Result.OK(usualService.queryAreas(3));
    }

    /**
     * 通过code查询区域
     */
    @GetMapping(value = {"/area/{code}"})
    public Result<?> queryProvinceByCode(@PathVariable("code") String code) {
        return Result.OK(usualService.queryAreaByCode(code));
    }

    /**
     * 通过名字查询区域
     */
    @GetMapping("/area/name/{name}")
    public Result<?> queryProvinceByName(@PathVariable("name") String name) {
        return Result.OK(usualService.queryAreaByName(name, 1));
    }

}
